package com.banhujiu.lakalaPlugin.utils;


import com.banhujiu.lakalaPlugin.config.LKLConfig;
import com.banhujiu.lakalaPlugin.exceptions.LklApiException;
import com.banhujiu.lakalaPlugin.exceptions.ValidationFailureException;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.support.ApplicationObjectSupport;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author 刘博文
 * @date 2017/4/10 0010 11:43
 */
public class LKLSignatureUtil extends ApplicationObjectSupport implements InitializingBean {
	protected final Log logger = LogFactory.getLog(getClass());

	private LKLConfig config;

	private String publicKeyFile;

	private String charset;

	public boolean rsaCheckV1(Map<String, String> params) {
		if (StringUtils.isEmpty(publicKeyFile)) {
			throw new LklApiException("请配置公钥地址");
		}
		String publicKey = getPublicKey(publicKeyFile);
		if (StringUtils.isEmpty(publicKey)) {
			throw new LklApiException("获取公钥内容失败");
		}
		return this.rsaCheckV1(params, publicKey);
	}

	public boolean rsaCheckV1(Map<String, String> params, String publicKey) {
		return this.rsaCheckV1(params, publicKey, this.charset);
	}

	public boolean rsaCheckV1(Map<String, String> params, String publicKey, String charset) {
		String sign = params.get("sign");
		String content = getSignCheckContentV1(params);
		return rsaCheckContent(content, sign, publicKey, charset);
	}

	private static String getPublicKey(String path) {
		try{
			InputStream is = LKLSignatureUtil.class.getResourceAsStream(path);
			return IOUtils.toString(is);
		}catch (Exception e){
			e.printStackTrace();
		}
		try {
			BufferedReader br = new BufferedReader(new FileReader(path));
			return br.readLine();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public String getSignCheckContentV1(Map<String, String> params) {
		if (params == null) {
			return null;
		} else {
			params.remove("sign");
			params.remove("sign_type");
			StringBuilder content = new StringBuilder();
			List<String> keys = new ArrayList<String>();
			keys.addAll(params.keySet());
			Collections.sort(keys);
			String key;
			String value;
			for (int i = 0; i < keys.size(); ++i) {
				key = keys.get(i);
				value = params.get(key);
				content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
			}
			return content.toString();
		}
	}

	public boolean rsaCheckContent(String content, String sign, String publicKey, String charset) {
		if (StringUtils.isEmpty(content) || StringUtils.isEmpty(sign) || StringUtils.isEmpty(publicKey)) {
			throw new LklApiException("校验参数不能为空");
		}
		try {
			PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
			Signature signature = Signature.getInstance("SHA1WithRSA");
			signature.initVerify(pubKey);
			if (StringUtils.isEmpty(charset)) {
				signature.update(content.getBytes());
			} else {
				signature.update(content.getBytes(charset));
			}

			return signature.verify(Base64.decodeBase64(sign.getBytes()));
		} catch (Exception var6) {
			throw new ValidationFailureException("RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, var6);
		}
	}

	public PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
		StringWriter writer = new StringWriter();
		StreamUtil.io(new InputStreamReader(ins), writer);
		byte[] encodedKey = writer.toString().getBytes();
		encodedKey = Base64.decodeBase64(encodedKey);
		return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
	}

	public String getPublicKeyFile() {
		return publicKeyFile;
	}

	public void setPublicKeyFile(String publicKeyFile) {
		this.publicKeyFile = publicKeyFile;
	}


	/**
	 * 初始化config
	 * @throws NoSuchBeanDefinitionException 如果未设置config，且Spring上下文中也没有唯一的LKLConfig bean
	 * @throws SecurityException  如果未设置GroupTemplate，且Spring上下文中有多个LKLConfig bean
	 * @throws NoSuchFieldException
	 */
	@Override
	public void afterPropertiesSet()
			throws NoSuchBeanDefinitionException,SecurityException, NoSuchFieldException {
		logger.info("config初始化开始");
		if(config == null){
			config = getApplicationContext().getBean(LKLConfig.class);
			this.charset = config.getCharset();
			this.publicKeyFile = config.getPublicKeyFile();
		}
		logger.info("config初始化开始");
	}

	@Override
	public String toString() {
		return "LKLSignatureUtil{" +
				"config=" + config +
				", publicKeyFile='" + publicKeyFile + '\'' +
				", charset='" + charset + '\'' +
				'}';
	}
}
